import {
  GetYearsParams,
  DataTemplate,
  GetCurrentDateReturn,
  YearChangeEvent,
  MonthChangeEvent,
  DayChangeEvent,
  WeekChangeEvent,
  HourChangeEvent,
  MinuteChangeEvent,
  SecondChangeEvent
} from '../interfaces'
import { 
  isLeapYear,
  isDataType,
  getCurrentDate,
  getCollectionValues,
  parseDate,
  observeTemplate
} from '../utils'
class Core {
  template: DataTemplate;
  constructor(date?: string) {
    this.template = this.getTemplate(date);
    // 监听模板数据
    observeTemplate(
      this.template,
      this.handleTemplateChange,
      ['currentYear','currentMonth','currentWeek','currentDay','currentHour','currentMinute','currentSecond']
    )
  }

  public getYears(params: GetYearsParams = {}): number[] {
    let { year, type='end', number=10, start, end} = params;

    if (!isDataType(year, 'Number')) {
      year = getCurrentDate().y
    }
    
    if (!isDataType(number, 'Number')) {
      number = 10
    }

    if (!['start', 'middle', 'end'].includes(type)) {
      type = 'end';
      console.warn(`getYears方法不支持${type}类型，type重置end`)
    }

    if (type === 'start') {
      end = number - 1;
    }
    if (type === 'end') {
      start = number - 1;
    }
    if (type === 'middle') {
      start = number / 2 - 1;
      end = number / 2 - 1;
    }
    let years = [];
    if (start) {
      let val = year;
      for (let i = 0; i < start; i++) {
        years.unshift(--val);
      }
    }
    years.push(year)
    if (end) {
      let val = year;
      for (let i = 0; i < end; i++) {
        years.push(++val);
      }
    }
    let len = years.length;
    if (len !== number) {
      years.push(years[len-1] + 1);
    }
    return years;
  }

  public setYear(params: YearChangeEvent): DataTemplate {
    const { currentYear } = this.template
    let year = currentYear;
    if (params.y === year) return this.template;
    if (params.y) {
      year = params.y;
    } else if (params.action === 'prev') {
      year -= 1;
    } else if (params.action === 'next') {
      year += 1;
    }
    this.template.currentYear = year;
    this.template.years = this.getYears({ year });
    return this.template;
  }

  public getMonths(): string[] {
    return getCollectionValues()
  }

  public setMonth(params: MonthChangeEvent): DataTemplate {
    const { currentMonth } = this.template
    let month = currentMonth;
    if (params.m === month) return this.template;
    if (params.m) {
      month = params.m;
    } else if (params.action === 'prev') {
      month -= 1;
    } else if (params.action === 'next') {
      month += 1;
    }
    if (month > 12) {
      month = 1;
      this.template.currentYear += 1;   
    }
    this.template.currentMonth = month;
    return this.template;
  }

  public getDays(year: number, month: number): string[] {
    return getCollectionValues({
      start: 1,
      end: this.getMonthDays(year, month),
    })
  }

  public setDay(params: DayChangeEvent): DataTemplate {
    const { currentDay, currentYear, currentMonth } = this.template
    let day = currentDay;
    if (params.d === day) return this.template;
    if (params.d) {
      day = params.d;
    } else if (params.action === 'prev') {
      day -= 1;
    } else if (params.action === 'next') {
      day += 1;
    }
    const currentMonthDay = this.getMonthDays(currentYear, currentMonth);
    if (day > currentMonthDay) {
      this.setMonth({action: 'next'})
      day = 1;
    }
    this.template.currentDay = day;
    return this.template;
  }

  public getWeek(y: number, m: number, d: number): number {
    const startWeek = 1;
    if (m < 3) {
      m += 12;
      --y;
    }
    return (d + startWeek + 2 * m + Math.floor(3 * (m + 1) / 5) + y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400)) % 7;
  }

  public setWeek(params: WeekChangeEvent): DataTemplate {
    const { currentWeek } = this.template
    let week = currentWeek;
    if (params.w === week) return this.template;
    if (params.w) {
      week = params.w;
    } else if (params.action === 'prev') {
      week -= 1;
    } else if (params.action === 'next') {
      week += 1;
    }
    if (week) {}
    return this.template;
  }

  public setHour(params: HourChangeEvent): DataTemplate {
    const { currentHour } = this.template
    let h = currentHour;
    if (params.h === h) return this.template;
    if (params.h) {
      h = params.h;
    } else if (params.action === 'prev') {
      h -= 1;
    } else if (params.action === 'next') {
      h += 1;
    }
    if (h > 23) {
      h = 0; 
    } else if (h < 0) {
      h = 23;
    }
    this.template.currentHour = h;
    return this.template;
  }
  public setMinute(params: MinuteChangeEvent): DataTemplate {
    const { currentMinute } = this.template
    let mm = currentMinute;
    if (params.mm === mm) return this.template;
    if (params.mm) {
      mm = params.mm;
    } else if (params.action === 'prev') {
      mm -= 1;
    } else if (params.action === 'next') {
      mm += 1;
    }
    if (mm > 59) {
      mm = 0; 
    } else if (mm < 0) {
      mm = 59;
    }
    this.template.currentMinute = mm;
    return this.template;
  }
  public setSecond(params: SecondChangeEvent): DataTemplate {
    const { currentSecond } = this.template
    let ss = currentSecond;
    if (params.ss === ss) return this.template;
    if (params.ss) {
      ss = params.ss;
    } else if (params.action === 'prev') {
      ss -= 1;
    } else if (params.action === 'next') {
      ss += 1;
    }
    if (ss > 59) {
      ss = 0; 
    } else if (ss < 0) {
      ss = 59;
    }
    this.template.currentSecond = ss;
    return this.template;
  }
  private getMonthDays(year: number, month: number) {
    month -= 1;
    return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
  }

  private getTemplate(val?: string): DataTemplate {
    let dateData: GetCurrentDateReturn;
    if (val) {
      dateData = parseDate(val);
    } else {
      dateData = getCurrentDate();
    }
    const { y, m, d, h, mm, ss, date, dateTime } = dateData;
    let template = {
      years: this.getYears({ year: y }),
      months: this.getMonths(),
      days: this.getDays(y, m),
      hours: getCollectionValues({ start: 0, end: 23 }),
      minutes: getCollectionValues({ start: 0, end: 59 }),
      seconds: getCollectionValues({ start: 0, end: 59 }),
      currentYear: y,
      currentMonth: m,
      currentWeek: this.getWeek(y, m, d),
      currentDay: d,
      currentHour: h,
      currentMinute: mm,
      currentSecond: ss,
      date,
      dateTime,
      format() {
        return ''
      },
      extend: {}
    }
    return template;
  }

  private handleTemplateChange(key: string, template: DataTemplate) {
    const { currentYear, currentMonth, currentDay, currentHour, currentMinute, currentSecond } = template;
    // 处理闰年2月份29日 切换到平年的情况
    if (key === 'currentYear' && currentMonth === 2 && currentDay === 29 && !isLeapYear(currentYear)) {
      this.template.currentDay = 28;
    }
    this.template.date = `${currentYear}-${currentMonth}-${currentDay}`
    this.template.date = `${this.template.date} ${currentHour}:${currentMinute}:${currentSecond}`
  }
}
export default Core
